#include "UnitTest.h"
#include "Console.h"

const static U8 MAX_GROUPS = 128;
const static U32 MAX_TESTS = 1024;

namespace CEngine {

UnitTest::UnitTest(void)
    :   stack(32000),
        groupName(NULL),
        tests(NULL),
        testCount(0),
        groupCount(0)
{
    groupName = (U64*)stack.alloc(MAX_GROUPS * sizeof(U64));
    tests = (Test*)stack.alloc(MAX_TESTS * sizeof(Test));

    for (U8 i = 0; i < MAX_GROUPS; ++i) {
        groupName[i] = 0;
    }

    for (U32 i = 0; i < MAX_TESTS; ++i) {
        tests[i].testName = NULL;
        tests[i].groupID = 0;
        tests[i].result = false;
    }
}

UnitTest::~UnitTest(void) {}

void
UnitTest::createTestGroup(const CHAR* name) {
    U32 length = 1;

    for (U32 i = 0; name[i] != '\0'; ++i) {
        ++length;
    }

    groupName[groupCount] = (U64)stack.alloc(length);
    ++groupCount;

    CHAR* address = (CHAR*)groupName[groupCount - 1];
    for (U32 i = 0; i < length; ++i) {
        address[i] = name[i];
    }
}

void
UnitTest::test(const CHAR* group, const CHAR* testName, bool result) {
    bool groupExists = false;
    U8 count;

    for (count = 0; count < groupCount; ++count) {
        CHAR* address = (CHAR*)groupName[count];
        bool failed = false;
        for (U32 i = 0; address[i] != '\0'; ++i) {
            if(group[i] != address[i]) {
                failed = true;
            }
        }
        if(failed) {
            continue;
        }
        else {
            groupExists = true;
            break;
        }
    }
    if(!groupExists) {
        return;
    }

    U32 length = 1;

    for (U32 i = 0; testName[i] != '\0'; ++i) {
        ++length;
    }

    tests[testCount].testName = (CHAR*)stack.alloc(length);
    tests[testCount].groupID = count;
    tests[testCount].result = result;
    ++testCount;

    CHAR* address = tests[testCount - 1].testName;

    for (U32 i = 0; i < length; ++i) {
        address[i] = testName[i];
    }
}

void
UnitTest::printResults(void) const {
    for (U8 i = 0; i < groupCount; ++i) {
        U32 totalTests = 0;
        U32 passedTests = 0;

        for (U32 c = 0; c < testCount; ++c) {
            if(tests[c].groupID == i) {
                ++totalTests;
                if(tests[c].result)
                    ++passedTests;
            }
        }
        if(totalTests == passedTests) {
            Console::print("%q%s: %d of %d tests passed!\n%r", Console::LGREEN, (CHAR*)groupName[i], passedTests, totalTests);
        }
        else if(passedTests > 0){
            Console::print("%q%s: %d of %d tests passed!\n%r", Console::LYELLOW, (CHAR*)groupName[i], passedTests, totalTests);
        }
        else {
            Console::print("%q%s: %d of %d tests passed!\n%r", Console::LRED, (CHAR*)groupName[i], passedTests, totalTests);
        }

        for (U32 c = 0; c < testCount; ++c) {
            if(tests[c].groupID == i) {
                if(tests[c].result)
                    Console::print("%q\t%s: PASSED\n%r", Console::LGREEN, (CHAR*)tests[c].testName);
                else
                    Console::print("%q\t%s: FAILED\n%r", Console::LRED, (CHAR*)tests[c].testName);
            }
        }
    }
}

}
